<!-- please do not entitify this javascript code; its for on page demo -->
<script>
var customarray=new Array('an apple','alligator','elephant','pear','kingbird','kingbolt', 'kingcraft','kingcup','kingdom','kingfisher','kingpin');
function addEvent(obj,event_name,func_name){
	if (obj.attachEvent){
		obj.attachEvent("on"+event_name, func_name);
	}else if(obj.addEventListener){
		obj.addEventListener(event_name,func_name,true);
	}else{
		obj["on"+event_name] = func_name;
	}
}
function removeEvent(obj,event_name,func_name){
	if (obj.detachEvent){
		obj.detachEvent("on"+event_name,func_name);
	}else if(obj.removeEventListener){
		obj.removeEventListener(event_name,func_name,true);
	}else{
		obj["on"+event_name] = null;
	}
}
function stopEvent(evt){
	evt || window.event;
	if (evt.stopPropagation){
		evt.stopPropagation();
		evt.preventDefault();
	}else if(typeof evt.cancelBubble != "undefined"){
		evt.cancelBubble = true;
		evt.returnValue = false;
	}
	return false;
}
function getElement(evt){
	if (window.event){
		return window.event.srcElement;
	}else{
		return evt.currentTarget;
	}
}
function getTargetElement(evt){
	if (window.event){
		return window.event.srcElement;
	}else{
		return evt.target;
	}
}
function stopSelect(obj){
	if (typeof obj.onselectstart != 'undefined'){
		addEvent(obj,"selectstart",function(){ return false;});
	}
}
function getCaretEnd(obj){
	if(typeof obj.selectionEnd != "undefined"){
		return obj.selectionEnd;
	}else if(document.selection&&document.selection.createRange){
		var M=document.selection.createRange();
		try{
			var Lp = M.duplicate();
			Lp.moveToElementText(obj);
		}catch(e){
			var Lp=obj.createTextRange();
		}
		Lp.setEndPoint("EndToEnd",M);
		var rb=Lp.text.length;
		if(rb>obj.value.length){
			return -1;
		}
		return rb;
	}
}
function getCaretStart(obj){
	if(typeof obj.selectionStart != "undefined"){
		return obj.selectionStart;
	}else if(document.selection&&document.selection.createRange){
		var M=document.selection.createRange();
		try{
			var Lp = M.duplicate();
			Lp.moveToElementText(obj);
		}catch(e){
			var Lp=obj.createTextRange();
		}
		Lp.setEndPoint("EndToStart",M);
		var rb=Lp.text.length;
		if(rb>obj.value.length){
			return -1;
		}
		return rb;
	}
}
function setCaret(obj,l){
	obj.focus();
	if (obj.setSelectionRange){
		obj.setSelectionRange(l,l);
	}else if(obj.createTextRange){
		m = obj.createTextRange();		
		m.moveStart('character',l);
		m.collapse();
		m.select();
	}
}
function setSelection(obj,s,e){
	obj.focus();
	if (obj.setSelectionRange){
		obj.setSelectionRange(s,e);
	}else if(obj.createTextRange){
		m = obj.createTextRange();		
		m.moveStart('character',s);
		m.moveEnd('character',e);
		m.select();
	}
}
String.prototype.addslashes = function(){
	return this.replace(/(["\\\.\|\[\]\^\*\+\?\$\(\)])/g, '\\$1');
}
String.prototype.trim = function () {
    return this.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1");
};
function curTop(obj){
	toreturn = 0;
	while(obj){
		toreturn += obj.offsetTop;
		obj = obj.offsetParent;
	}
	return toreturn;
}
function curLeft(obj){
	toreturn = 0;
	while(obj){
		toreturn += obj.offsetLeft;
		obj = obj.offsetParent;
	}
	return toreturn;
}
function isNumber(a) {
    return typeof a == 'number' && isFinite(a);
}
function replaceHTML(obj,text){
	while(el = obj.childNodes[0]){
		obj.removeChild(el);
	};
	obj.appendChild(document.createTextNode(text));
}

function actb(obj,ca){
	/* ---- Public Variables ---- */
	this.actb_timeOut = -1; // Autocomplete Timeout in ms (-1: autocomplete never time out)
	this.actb_lim = 4;    // Number of elements autocomplete can show (-1: no limit)
	this.actb_firstText = false; // should the auto complete be limited to the beginning of keyword?
	this.actb_mouse = true; // Enable Mouse Support
	this.actb_delimiter = new Array(';',',');  // Delimiter for multiple autocomplete. Set it to empty array for single autocomplete
	this.actb_startcheck = 1; // Show widget only after this number of characters is typed in.
	/* ---- Public Variables ---- */

	/* --- Styles --- */
	this.actb_bgColor = '#888888';
	this.actb_textColor = '#FFFFFF';
	this.actb_hColor = '#000000';
	this.actb_fFamily = 'Verdana';
	this.actb_fSize = '11px';
	this.actb_hStyle = 'text-decoration:underline;font-weight="bold"';
	/* --- Styles --- */

	/* ---- Private Variables ---- */
	var actb_delimwords = new Array();
	var actb_cdelimword = 0;
	var actb_delimchar = new Array();
	var actb_display = false;
	var actb_pos = 0;
	var actb_total = 0;
	var actb_curr = null;
	var actb_rangeu = 0;
	var actb_ranged = 0;
	var actb_bool = new Array();
	var actb_pre = 0;
	var actb_toid;
	var actb_tomake = false;
	var actb_getpre = "";
	var actb_mouse_on_list = 1;
	var actb_kwcount = 0;
	var actb_caretmove = false;
	this.actb_keywords = new Array();
	/* ---- Private Variables---- */
	
	this.actb_keywords = ca;
	var actb_self = this;

	actb_curr = obj;
	
	addEvent(actb_curr,"focus",actb_setup);
	function actb_setup(){
		addEvent(document,"keydown",actb_checkkey);
		addEvent(actb_curr,"blur",actb_clear);
		addEvent(document,"keypress",actb_keypress);
	}

	function actb_clear(evt){
		if (!evt) evt = event;
		removeEvent(document,"keydown",actb_checkkey);
		removeEvent(actb_curr,"blur",actb_clear);
		removeEvent(document,"keypress",actb_keypress);
		actb_removedisp();
	}
	function actb_parse(n){
		if (actb_self.actb_delimiter.length > 0){
			var t = actb_delimwords[actb_cdelimword].trim().addslashes();
			var plen = actb_delimwords[actb_cdelimword].trim().length;
		}else{
			var t = actb_curr.value.addslashes();
			var plen = actb_curr.value.length;
		}
		var tobuild = '';
		var i;

		if (actb_self.actb_firstText){
			var re = new RegExp("^" + t, "i");
		}else{
			var re = new RegExp(t, "i");
		}
		var p = n.search(re);
				
		for (i=0;i<p;i++){
			tobuild += n.substr(i,1);
		}
		tobuild += "<font style='"+(actb_self.actb_hStyle)+"'>"
		for (i=p;i<plen+p;i++){
			tobuild += n.substr(i,1);
		}
		tobuild += "</font>";
			for (i=plen+p;i<n.length;i++){
			tobuild += n.substr(i,1);
		}
		return tobuild;
	}
	function actb_generate(){
		if (document.getElementById('tat_table')){ actb_display = false;document.body.removeChild(document.getElementById('tat_table')); } 
		if (actb_kwcount == 0){
			actb_display = false;
			return;
		}
		a = document.createElement('table');
		a.cellSpacing='1px';
		a.cellPadding='2px';
		a.style.position='absolute';
		a.style.top = eval(curTop(actb_curr) + actb_curr.offsetHeight) + "px";
		a.style.left = curLeft(actb_curr) + "px";
		a.style.backgroundColor=actb_self.actb_bgColor;
		a.id = 'tat_table';
		document.body.appendChild(a);
		var i;
		var first = true;
		var j = 1;
		if (actb_self.actb_mouse){
			a.onmouseout = actb_table_unfocus;
			a.onmouseover = actb_table_focus;
		}
		var counter = 0;
		for (i=0;i<actb_self.actb_keywords.length;i++){
			if (actb_bool[i]){
				counter++;
				r = a.insertRow(-1);
				if (first && !actb_tomake){
					r.style.backgroundColor = actb_self.actb_hColor;
					first = false;
					actb_pos = counter;
				}else if(actb_pre == i){
					r.style.backgroundColor = actb_self.actb_hColor;
					first = false;
					actb_pos = counter;
				}else{
					r.style.backgroundColor = actb_self.actb_bgColor;
				}
				r.id = 'tat_tr'+(j);
				c = r.insertCell(-1);
				c.style.color = actb_self.actb_textColor;
				c.style.fontFamily = actb_self.actb_fFamily;
				c.style.fontSize = actb_self.actb_fSize;
				c.innerHTML = actb_parse(actb_self.actb_keywords[i]);
				c.id = 'tat_td'+(j);
				c.setAttribute('pos',j);
				if (actb_self.actb_mouse){
					c.style.cursor = 'pointer';
					c.onclick=actb_mouseclick;
					c.onmouseover = actb_table_highlight;
				}
				j++;
			}
			if (j - 1 == actb_self.actb_lim && j < actb_total){
				r = a.insertRow(-1);
				r.style.backgroundColor = actb_self.actb_bgColor;
				c = r.insertCell(-1);
				c.style.color = actb_self.actb_textColor;
				c.style.fontFamily = 'arial narrow';
				c.style.fontSize = actb_self.actb_fSize;
				c.align='center';
				replaceHTML(c,'\\/');
				if (actb_self.actb_mouse){
					c.style.cursor = 'pointer';
					c.onclick = actb_mouse_down;
				}
				break;
			}
		}
		actb_rangeu = 1;
		actb_ranged = j-1;
		actb_display = true;
		if (actb_pos <= 0) actb_pos = 1;
	}
	function actb_remake(){
		document.body.removeChild(document.getElementById('tat_table'));
		a = document.createElement('table');
		a.cellSpacing='1px';
		a.cellPadding='2px';
		a.style.position='absolute';
		a.style.top = eval(curTop(actb_curr) + actb_curr.offsetHeight) + "px";
		a.style.left = curLeft(actb_curr) + "px";
		a.style.backgroundColor=actb_self.actb_bgColor;
		a.id = 'tat_table';
		if (actb_self.actb_mouse){
			a.onmouseout= actb_table_unfocus;
			a.onmouseover=actb_table_focus;
		}
		document.body.appendChild(a);
		var i;
		var first = true;
		var j = 1;
		if (actb_rangeu > 1){
			r = a.insertRow(-1);
			r.style.backgroundColor = actb_self.actb_bgColor;
			c = r.insertCell(-1);
			c.style.color = actb_self.actb_textColor;
			c.style.fontFamily = 'arial narrow';
			c.style.fontSize = actb_self.actb_fSize;
			c.align='center';
			replaceHTML(c,'/\\');
			if (actb_self.actb_mouse){
				c.style.cursor = 'pointer';
				c.onclick = actb_mouse_up;
			}
		}
		for (i=0;i<actb_self.actb_keywords.length;i++){
			if (actb_bool[i]){
				if (j >= actb_rangeu && j <= actb_ranged){
					r = a.insertRow(-1);
					r.style.backgroundColor = actb_self.actb_bgColor;
					r.id = 'tat_tr'+(j);
					c = r.insertCell(-1);
					c.style.color = actb_self.actb_textColor;
					c.style.fontFamily = actb_self.actb_fFamily;
					c.style.fontSize = actb_self.actb_fSize;
					c.innerHTML = actb_parse(actb_self.actb_keywords[i]);
					c.id = 'tat_td'+(j);
					c.setAttribute('pos',j);
					if (actb_self.actb_mouse){
						c.style.cursor = 'pointer';
						c.onclick=actb_mouseclick;
						c.onmouseover = actb_table_highlight;
					}
					j++;
				}else{
					j++;
				}
			}
			if (j > actb_ranged) break;
		}
		if (j-1 < actb_total){
			r = a.insertRow(-1);
			r.style.backgroundColor = actb_self.actb_bgColor;
			c = r.insertCell(-1);
			c.style.color = actb_self.actb_textColor;
			c.style.fontFamily = 'arial narrow';
			c.style.fontSize = actb_self.actb_fSize;
			c.align='center';
			replaceHTML(c,'\\/');
			if (actb_self.actb_mouse){
				c.style.cursor = 'pointer';
				c.onclick = actb_mouse_down;
			}
		}
	}
	function actb_goup(){
		if (!actb_display) return;
		if (actb_pos == 1) return;
		document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_bgColor;
		actb_pos--;
		if (actb_pos < actb_rangeu) actb_moveup();
		document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_hColor;
		if (actb_toid) clearTimeout(actb_toid);
		if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list=0;actb_removedisp();},actb_self.actb_timeOut);
	}
	function actb_godown(){
		if (!actb_display) return;
		if (actb_pos == actb_total) return;
		document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_bgColor;
		actb_pos++;
		if (actb_pos > actb_ranged) actb_movedown();
		document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_hColor;
		if (actb_toid) clearTimeout(actb_toid);
		if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list=0;actb_removedisp();},actb_self.actb_timeOut);
	}
	function actb_movedown(){
		actb_rangeu++;
		actb_ranged++;
		actb_remake();
	}
	function actb_moveup(){
		actb_rangeu--;
		actb_ranged--;
		actb_remake();
	}

	/* Mouse */
	function actb_mouse_down(){
		document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_bgColor;
		actb_pos++;
		actb_movedown();
		document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_hColor;
		actb_curr.focus();
		actb_mouse_on_list = 0;
		if (actb_toid) clearTimeout(actb_toid);
		if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list=0;actb_removedisp();},actb_self.actb_timeOut);
	}
	function actb_mouse_up(evt){
		if (!evt) evt = event;
		if (evt.stopPropagation){
			evt.stopPropagation();
		}else{
			evt.cancelBubble = true;
		}
		document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_bgColor;
		actb_pos--;
		actb_moveup();
		document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_hColor;
		actb_curr.focus();
		actb_mouse_on_list = 0;
		if (actb_toid) clearTimeout(actb_toid);
		if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list=0;actb_removedisp();},actb_self.actb_timeOut);
	}
	function actb_mouseclick(evt){
		if (!evt) evt = event;
		if (!actb_display) return;
		actb_mouse_on_list = 0;
		actb_pos = this.getAttribute('pos');
		actb_penter();
	}
	function actb_table_focus(){
		actb_mouse_on_list = 1;
	}
	function actb_table_unfocus(){
		actb_mouse_on_list = 0;
		if (actb_toid) clearTimeout(actb_toid);
		if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list = 0;actb_removedisp();},actb_self.actb_timeOut);
	}
	function actb_table_highlight(){
		actb_mouse_on_list = 1;
		document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_bgColor;
		actb_pos = this.getAttribute('pos');
		while (actb_pos < actb_rangeu) actb_moveup();
		while (actb_pos > actb_ranged) actb_movedown();
		document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_hColor;
		if (actb_toid) clearTimeout(actb_toid);
		if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list = 0;actb_removedisp();},actb_self.actb_timeOut);
	}
	/* ---- */

	function actb_insertword(a){
		if (actb_self.actb_delimiter.length > 0){
			str = '';
			l=0;
			for (i=0;i<actb_delimwords.length;i++){
				if (actb_cdelimword == i){
					prespace = postspace = '';
					gotbreak = false;
					for (j=0;j<actb_delimwords[i].length;++j){
						if (actb_delimwords[i].charAt(j) != ' '){
							gotbreak = true;
							break;
						}
						prespace += ' ';
					}
					for (j=actb_delimwords[i].length-1;j>=0;--j){
						if (actb_delimwords[i].charAt(j) != ' ') break;
						postspace += ' ';
					}
					str += prespace;
					str += a;
					l = str.length;
					if (gotbreak) str += postspace;
				}else{
					str += actb_delimwords[i];
				}
				if (i != actb_delimwords.length - 1){
					str += actb_delimchar[i];
				}
			}
			actb_curr.value = str;
			setCaret(actb_curr,l);
		}else{
			actb_curr.value = a;
		}
		actb_mouse_on_list = 0;
		actb_removedisp();
	}
	function actb_penter(){
		if (!actb_display) return;
		actb_display = false;
		var word = '';
		var c = 0;
		for (var i=0;i<=actb_self.actb_keywords.length;i++){
			if (actb_bool[i]) c++;
			if (c == actb_pos){
				word = actb_self.actb_keywords[i];
				break;
			}
		}
		actb_insertword(word);
		l = getCaretStart(actb_curr);
	}
	function actb_removedisp(){
		if (actb_mouse_on_list==0){
			actb_display = 0;
			if (document.getElementById('tat_table')){ document.body.removeChild(document.getElementById('tat_table')); }
			if (actb_toid) clearTimeout(actb_toid);
		}
	}
	function actb_keypress(e){
		if (actb_caretmove) stopEvent(e);
		return !actb_caretmove;
	}
	function actb_checkkey(evt){
		if (!evt) evt = event;
		a = evt.keyCode;
		caret_pos_start = getCaretStart(actb_curr);
		actb_caretmove = 0;
		switch (a){
			case 38:
				actb_goup();
				actb_caretmove = 1;
				return false;
				break;
			case 40:
				actb_godown();
				actb_caretmove = 1;
				return false;
				break;
			case 13: case 9:
				if (actb_display){
					actb_caretmove = 1;
					actb_penter();
					return false;
				}else{
					return true;
				}
				break;
			default:
				setTimeout(function(){actb_tocomplete(a)},50);
				break;
		}
	}

	function actb_tocomplete(kc){
		if (kc == 38 || kc == 40 || kc == 13) return;
		var i;
		if (actb_display){ 
			var word = 0;
			var c = 0;
			for (var i=0;i<=actb_self.actb_keywords.length;i++){
				if (actb_bool[i]) c++;
				if (c == actb_pos){
					word = i;
					break;
				}
			}
			actb_pre = word;
		}else{ actb_pre = -1};
		
		if (actb_curr.value == ''){
			actb_mouse_on_list = 0;
			actb_removedisp();
			return;
		}
		if (actb_self.actb_delimiter.length > 0){
			caret_pos_start = getCaretStart(actb_curr);
			caret_pos_end = getCaretEnd(actb_curr);
			
			delim_split = '';
			for (i=0;i<actb_self.actb_delimiter.length;i++){
				delim_split += actb_self.actb_delimiter[i];
			}
			delim_split = delim_split.addslashes();
			delim_split_rx = new RegExp("(["+delim_split+"])");
			c = 0;
			actb_delimwords = new Array();
			actb_delimwords[0] = '';
			for (i=0,j=actb_curr.value.length;i<actb_curr.value.length;i++,j--){
				if (actb_curr.value.substr(i,j).search(delim_split_rx) == 0){
					ma = actb_curr.value.substr(i,j).match(delim_split_rx);
					actb_delimchar[c] = ma[1];
					c++;
					actb_delimwords[c] = '';
				}else{
					actb_delimwords[c] += actb_curr.value.charAt(i);
				}
			}

			var l = 0;
			actb_cdelimword = -1;
			for (i=0;i<actb_delimwords.length;i++){
				if (caret_pos_end >= l && caret_pos_end <= l + actb_delimwords[i].length){
					actb_cdelimword = i;
				}
				l+=actb_delimwords[i].length + 1;
			}
			var ot = actb_delimwords[actb_cdelimword].trim(); 
			var t = actb_delimwords[actb_cdelimword].addslashes().trim();
		}else{
			var ot = actb_curr.value;
			var t = actb_curr.value.addslashes();
		}
		if (ot.length == 0){
			actb_mouse_on_list = 0;
			actb_removedisp();
		}
		if (ot.length < actb_self.actb_startcheck) return this;
		if (actb_self.actb_firstText){
			var re = new RegExp("^" + t, "i");
		}else{
			var re = new RegExp(t, "i");
		}

		actb_total = 0;
		actb_tomake = false;
		actb_kwcount = 0;
		for (i=0;i<actb_self.actb_keywords.length;i++){
			actb_bool[i] = false;
			if (re.test(actb_self.actb_keywords[i])){
				actb_total++;
				actb_bool[i] = true;
				actb_kwcount++;
				if (actb_pre == i) actb_tomake = true;
			}
		}

		if (actb_toid) clearTimeout(actb_toid);
		if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list = 0;actb_removedisp();},actb_self.actb_timeOut);
		actb_generate();
	}
	return this;
}
</script>
<UL class=download>
<LI><A href="http://www.codeproject.com/jscript/jsactb/actb.zip">Download source - 3.05 Kb</A> </LI></UL>
<H2>Introduction</H2>
<P>Most auto-complete textboxes may have a reverse effect on end-users. Instead of helping them get things done faster, they get irritated by design flaws made by the programmer. (Admittedly, I've made such design flaws too.)</P>
<P>I got to learn this lesson when designing my first auto-complete edit control, found <A href="http://www.codeproject.com/jscript/javaautocomplete1.asp">here</A>[<A title="New Window" href="http://www.codeproject.com/jscript/javaautocomplete1.asp" target=_blank>^</A>]. Although it seemingly looks intuitive, I forgot to consider the fact that what if the end-user wanted to type just 'ap' but the 'ple' appears out of nowhere? This means that the end-user would then have to hunt for, and press the delete key.</P>
<P>After seeing how GMail made its auto-complete, I took the idea and implemented my own version of the auto-complete control.</P>
<P>Auto-complete textbox control:</P>
<p><input type='textbox' id='actb_textbox' value=''>
<UL>
<LI><SMALL>Timeout: 3000ms</SMALL> 
<LI><SMALL>Deliminator: <B>;</B> and <b>,</b></SMALL> 
<LI><SMALL>Options: ('an apple','alligator','elephant','pear','kingbird','kingbolt', 'kingcraft','kingcup','kingdom','kingfisher','kingpin')</SMALL> </LI></UL>
</p>
<script>
actb(document.getElementById("actb_textbox"),customarray);
</script>
<H2>How does it work?</H2>
<P>The important event that will fire whenever the user press any key is <CODE>onkeydown</CODE>. The <CODE>onkeydown</CODE> event handles all the normal character input and is in charge of creating the auto-complete list. It also handles keys like 'up', 'down' and 'enter'.</P>
<P>Using the JavaScript <CODE>regexp()</CODE> object, the script will run through the array containing the keywords and match them one by one. After which, a <CODE lang=html>DIV</CODE> will be created dynamically using <CODE>document.createElement()</CODE>. Finally, when the user presses the 'Enter' key, the <CODE lang=html>DIV</CODE> will be detached and the input box updated.</P>
<P>The user can also select the options using the mouse. This is done through a three events: <CODE>onmouseover</CODE>,<CODE> onmouseout</CODE>, and <CODE>onclick</CODE>.</P>
<H2>How do you implement it into your own textbox?</H2>

<P>Firstly, include the <I>.js</I> file into your script:</P><PRE lang=jscript>&lt;script language="javascript" type="text/javascript" 
         src="actb.js"&gt;&lt;/script&gt;</PRE>

<P>Next, create an array (in JavaScript) containing the keywords:</P><PRE lang=jscript>customarray = new Array('apple','pear','mango','pineapple', 
         'orange','banana','durian', 'jackfruit','etc');</PRE>

<P>Apply the widget to your using javascript:</P><PRE lang=jscript>actb(document.getElementById('textbox_id'),customarray);</PRE>

<P>And you're done!</P>

<H2>Tweakability</H2>
<P>This auto-complete edit control has some customizable features:</P><PRE lang=jscript>
/* ---- Variables ---- */
this.actb_timeOut = -1; // Autocomplete Timeout in ms (-1: autocomplete never time out)
this.actb_lim = 4;    // Number of elements autocomplete can show (-1: no limit)
this.actb_firstText = false; // should the auto complete be limited to the beginning of keyword?
this.actb_mouse = true; // Enable Mouse Support
this.actb_delimiter = new Array(' ',',');  // Delimiter for multiple autocomplete. Set it to empty array for single autocomplete
this.actb_startcheck = 1; // Show widget only after this number of characters is typed in.
/* ---- Variables ---- */


/* --- Styles --- */
this.actb_bgColor = '#888888';
this.actb_textColor = '#FFFFFF';
this.actb_hColor = '#000000';
this.actb_fFamily = 'Verdana';
this.actb_fSize = '11px';
this.actb_hStyle = 'text-decoration:underline;font-weight="bold"';
/* --- Styles --- */ 

this.actb_keywords = new Array();
</PRE>
<P>The styles are pretty self-explanatory; tweak the values for best results for your own website. Firstly, the variable <CODE>actb_timeOut</CODE> controls how long the auto-complete list's timeout should be (i.e., after x ms, the list will disappear). By default, it is set to -1, which represents no timeout.</P>
<P>Next, the variable <CODE>actb_lim</CODE> limits the number of elements the list will show, to prevent over-spamming. If you do not want to set any limit, set it to -1.</P>
<P>Thirdly, the <CODE>actb_firstText</CODE> variable determines whether the match with the keywords-array should only start from the first character or if the match can be any arbitrary match within the keyword. For example, if <CODE>firstText</CODE> is set to true, then a given string "ello" will match with "hello".</P>
<P>Also, the <CODE>actb_mouse</CODE> variable determines whether the control should respond to mouse events. Mouse support works when user clicks on the auto-complete list that appears.</P>
<P>The <CODE>actb_delimiter</CODE> variable allows for the much requested multiple auto-complete feature. Set a custom delimiter, or even multiple delimiters, like semi-colon (;) or comma (,), and the engine will complete words separated by the given delimiter.</P>
<p>Lastly, <code>actb_startcheck</code> controls the number of characters that must be typed in before the textbox will display the control. Thanks to flyasfly for this suggestion. </p>
</P>

<H2>Implementations</H2>
<P>As of version 1.3, all of the above mentioned are public variables. This can be useful in emulating controls like Google Suggest. When you apply the control to your textbox using the actb function, it returns an object.</p>

<p><b>Changing the autocomplete list</b></p>
<pre lang=jscript>
obj = actb(document.getElementById('textbox_id'),customarray);
// ... after some time ...
obj.actb_keyword = new Array('this','is','a','new','set','of','keywords');
</pre>

<p><b>Multiple auto-complete textboxes</b></p>
<pre lang=jscript>
obj = <b>new</b> actb(document.getElementById('textbox_id'),customarray);
obj2 = <b>new</b> actb(document.getElementById('textbox2_id'),customarray2);
</pre>

<p><b>Multiple textboxes (different options)</b></p>
<pre lang=jscript>
obj = <b>new</b> actb(document.getElementById('textbox_id'),customarray);
  obj.actb_mouse = false; // no mouse support
obj2 = <b>new</b> actb(document.getElementById('textbox2_id'),customarray2);
  obj2.actb_startcheck = 2; // start actb only after 2nd character
</pre>

<H2>Todo</H2>
<ul>
<li>Add second array (customarrayDesc) for display desciption in the list (ex => [an apple : it's an apple] instead of [an apple]. Suggestion by angelo77 </li>
<li>Many other features suggested by CPians, some of which might be beyond me at the moment but I'll still try my best!</li>
</ul>

<H2>Tested browsers</H2>
<UL>
<LI>Internet Explorer 6.0.28 
<LI>Mozilla Firefox version 1.0.3 </LI></UL>

<H2>Finally...</H2>
<P>Thank you to all of you who has supported, modified, and offered your suggestions to the control! I'm extremely apologetic for the inactiveness of this project because of schoolwork etc. However, I still try my best to work on it whenever anyone has a new feature request!</P>

<h2>License</h2>
<p>This control will be, from effect of version 1.1, published under <strong><a href="http://creativecommons.org/licenses/by/2.0/">Creative Common License</a> [<A title="New Window" href="http://creativecommons.org/licenses/by/2.0/" target=_blank>^</A>]</strong></p>

<H2>Change Log</H2>
<UL>

<li><b>1.31: 12/5/2005</b></li>
<ul>
<li>Fix: Fix a bug with actb_bgColor styles due to typo</li>
<li>Fix: Now caret does not move away (firefox) when user presses enter or tab</li></ul>


<li><b>1.3: 8 May 2005</b></li>
<ul>
<li>Added: <code>actb_startcheck</code> the number of characters that start the widget contro. Thanks to flyasfly for suggestion</li>
<li>Change: All 'tweakabilities' and styles have been changed to public variable.</li>
<li>Fix: Fixed an IE-specific bug which prevents the caret position of textarea to be retrieved. Now widget works for textarea too.</li></ul>

<LI><B>1.2: 9 Apr 2005</B> 
<UL>
<LI>Change: Converted the code of actb widget to OOP
<LI>Fix: Mouse click bug that disallow autocomplete control from deleting itself
<LI>Added: the keywords array (<code>actb_keyword</code>) becomes a public variable, so it can be modified from the parent script</LI></UL>

<LI><B>1.1: 6 Dec 2004</B> 
<UL>
<LI>Fix: Metacharacters escaped before parsing with RegExp
<LI>Added: Multiple Delimiter 
<LI>Added: Tab now completes the text like enter
<li>Change: Now, only an event is needed for control to work; the rest are attached dynamically.
<LI>Fix: Bugs with caret position in Firefox: originally, 'up' and 'down' keys will change caret position in the textbox for firefox. This problem has been rectified. </LI></UL>

<LI><B>1.0: 23 Nov 2004</B> 
<UL>
<LI>Fix: some miscellaneouss bugs in mouse support (<CODE>actb_removedisp()</CODE> cannot be executed properly) 
<LI>Fix: <CODE>actb_timeout</CODE> now works fine with mouse support on 
<LI>Added: When user moves the mouse over each individual option, the options will be highlighted. 
<LI>Added: Multiple auto-complete! This works even if you're editing previous "fields". </LI></UL>

<LI><B>0.9: 6 Oct 2004</B> 
<UL>
<LI>Fix: A bug concerning <CODE>clientHeight</CODE> which apparently Mozilla does not support. Thanks Cameron Smith for pointing out. 
<LI>Added: This control now supports phrases with spaces in between. Thanks to Miguel Vieira. 
<LI>Added: This control has mouse support. Thanks to Alecacct and everyone for the idea. </LI></UL>

<LI><B>18 Aug 2004</B> 
<UL>
<LI>Basic engine created 
<LI>Article posted! </LI></UL></LI></UL>